home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / pppipcp.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  29KB  |  1,122 lines

  1. /*
  2.  *  PPPIPCP.C    -- negotiate IP parameters
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <time.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "iface.h"
  18. #include "slhc.h"
  19. #include "ppp.h"
  20. #include "pppfsm.h"
  21. #include "pppipcp.h"
  22. #include "cmdparse.h"
  23. #include "files.h"
  24. #include "trace.h"
  25.  
  26.  
  27. /* These defaults are defined in the PPP RFCs, and must not be changed */
  28. static struct ipcp_value_s ipcp_default = {
  29.     FALSE,            /* no need to negotiate defaults */
  30.  
  31.     0L,            /* no source address */
  32.     0L,            /* no destination address */
  33.  
  34.     0,            /* no compression protocol */
  35.     0,            /* no slots */
  36.     0            /* no slot compression */
  37. };
  38.  
  39. /* for test purposes, accept anything we understand */
  40. static int16 ipcp_negotiate = IPCP_N_ADDRESS | IPCP_N_COMPRESS;
  41.  
  42. static byte_t option_length[] = {
  43.      0,        /* unused */
  44.     10,        /* address */
  45.      6        /* compression */
  46. };
  47.  
  48.  
  49. static int doipcp_local        __ARGS((int argc, char *argv[], void *p));
  50. static int doipcp_open        __ARGS((int argc, char *argv[], void *p));
  51. static int doipcp_pool        __ARGS((int argc, char *argv[], void *p));
  52. static int doipcp_remote    __ARGS((int argc, char *argv[], void *p));
  53.  
  54. static int doipcp_address    __ARGS((int argc, char *argv[], void *p));
  55. static int doipcp_compress    __ARGS((int argc, char *argv[], void *p));
  56. static int doipcp_default    __ARGS((int argc, char *argv[], void *p));
  57.  
  58. static void ipcp_option __ARGS((struct mbuf **bpp,
  59.             struct ipcp_value_s *value_p,
  60.             byte_t o_type,
  61.             byte_t o_length,
  62.             struct mbuf **copy_bpp));
  63. static void ipcp_makeoptions __ARGS((struct mbuf **bpp,
  64.             struct ipcp_value_s *value_p,
  65.             int16 negotiating));
  66. static struct mbuf *ipcp_makereq __ARGS((struct fsm_s *fsm_p));
  67.  
  68. static int ipcp_check __ARGS((struct mbuf **bpp,
  69.             struct ipcp_s *ipcp_p,
  70.             struct ipcp_side_s *side_p,
  71.             struct option_hdr *option_p,
  72.             int request));
  73.  
  74. static int ipcp_request    __ARGS((struct fsm_s *fsm_p,
  75.             struct config_hdr *config,
  76.             struct mbuf *data));
  77. static int ipcp_ack    __ARGS((struct fsm_s *fsm_p,
  78.             struct config_hdr *config,
  79.             struct mbuf *data));
  80. static int ipcp_nak    __ARGS((struct fsm_s *fsm_p,
  81.             struct config_hdr *config,
  82.             struct mbuf *data));
  83. static int ipcp_reject    __ARGS((struct fsm_s *fsm_p,
  84.             struct config_hdr *config,
  85.             struct mbuf *data));
  86.  
  87. static void ipcp_reset    __ARGS((struct fsm_s *fsm_p));
  88.  
  89. static int32 ipcp_addr_idle __ARGS((int32 addr));
  90. static int32 ipcp_lookuppeer __ARGS((char *peerid));
  91. static int32 ipcp_poolnext __ARGS((struct ipcp_s *ipcp_p));
  92.  
  93. static void ipcp_starting __ARGS((struct fsm_s *fsm_p));
  94. static void ipcp_stopping __ARGS((struct fsm_s *fsm_p));
  95.  
  96. static void ipcp_closing __ARGS((struct fsm_s *fsm_p));
  97. static void ipcp_opening __ARGS((struct fsm_s *fsm_p));
  98.  
  99. static void ipcp_free    __ARGS((struct fsm_s *fsm_p));
  100.  
  101.  
  102. static struct fsm_constant_s ipcp_constants = {
  103.     "IPcp",
  104.     PPP_IPCP_PROTOCOL,
  105.     0x00FE,                /* codes 1-7 recognized */
  106.  
  107.     IPcp,
  108.     IPCP_REQ_TRY,
  109.     IPCP_NAK_TRY,
  110.     IPCP_TERM_TRY,
  111.     IPCP_TIMEOUT * 1000L,
  112.  
  113.     ipcp_free,
  114.  
  115.     ipcp_reset,
  116.     ipcp_starting,
  117.     ipcp_opening,
  118.     ipcp_closing,
  119.     ipcp_stopping,
  120.  
  121.     ipcp_makereq,
  122.     ipcp_request,
  123.     ipcp_ack,
  124.     ipcp_nak,
  125.     ipcp_reject,
  126. };
  127.  
  128.  
  129. /************************************************************************/
  130.  
  131. /* "ppp <iface> ipcp" subcommands */
  132. static struct cmds IPcpcmds[] = {
  133.     "close",    doppp_close,    0,    0,    NULLCHAR,
  134.     "listen",    doppp_passive,    0,    0,    NULLCHAR,
  135.     "local",    doipcp_local,    0,    0,    NULLCHAR,
  136.     "open",        doipcp_open,    0,    0,    NULLCHAR,
  137.     "pool",        doipcp_pool,    0,    0,    NULLCHAR,
  138.     "remote",    doipcp_remote,    0,    0,    NULLCHAR,
  139.     "timeout",    doppp_timeout,    0,    0,    NULLCHAR,
  140.     "try",        doppp_try,    0,    0,    NULLCHAR,
  141.     NULLCHAR,
  142. };
  143.  
  144. /* "ppp <iface> ipcp {local | remote}" subcommands */
  145. static struct cmds IPcpside_cmds[] = {
  146.     "address",    doipcp_address,    0,    0,    NULLCHAR,
  147.     "compress",    doipcp_compress,0,    0,    NULLCHAR,
  148.     "default",    doipcp_default,    0,    0,    NULLCHAR,
  149.     NULLCHAR,
  150. };
  151.  
  152.  
  153. int
  154. doppp_ipcp(argc,argv,p)
  155. int argc;
  156. char *argv[];
  157. void *p;
  158. {
  159.     register struct iface *ifp = p;
  160.     register struct ppp_s *ppp_p = ifp->edv;
  161.  
  162.     return subcmd(IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  163. }
  164.  
  165.  
  166. static int
  167. doipcp_local(argc,argv,p)
  168. int argc;
  169. char *argv[];
  170. void *p;
  171. {
  172.     struct fsm_s *fsm_p = p;
  173.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  174.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->local));
  175. }
  176.  
  177.  
  178. static int
  179. doipcp_open(argc,argv,p)
  180. int argc;
  181. char *argv[];
  182. void *p;
  183. {
  184.     struct fsm_s *fsm_p = p;
  185.  
  186.     doppp_active( argc, argv, p );
  187.  
  188.     if ( fsm_p->ppp_p->phase == pppREADY ) {
  189.         fsm_start( fsm_p );
  190.     }
  191.     return 0;
  192. }
  193.  
  194.  
  195. /* Set a pool of peer addresses for PPP interface */
  196. static int
  197. doipcp_pool(argc,argv,p)
  198. int argc;
  199. char *argv[];
  200. void *p;
  201. {
  202.     struct fsm_s *fsm_p = p;
  203.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  204.     int32 pool_addr;
  205.     int pool_cnt;
  206.  
  207.     if (argc < 2) {
  208.         if ( ipcp_p->peer_min == 0L ) {
  209.             tprintf("None");
  210.         } else {
  211.             tprintf("%s thru ", inet_ntoa(ipcp_p->peer_min));
  212.             tprintf("%s\n", inet_ntoa(ipcp_p->peer_max));
  213.         }
  214.         return 0;
  215.     }
  216.  
  217.     if ((pool_addr = resolve(argv[1])) == 0L) {
  218.         tprintf(Badhost,argv[1]);
  219.     }
  220.  
  221.     /* May specify a consecutive range of addresses; otherwise assume 1 */
  222.     if (argc < 3)
  223.         pool_cnt = 1;
  224.     else
  225.         pool_cnt = (int)strtol( argv[2], NULLCHARP, 0 );
  226.  
  227.     if (pool_cnt <= 0) {
  228.         tprintf("Pool count %s (%d) must be > 0\n");
  229.         return -1;
  230.     }
  231.  
  232.     ipcp_p->peer_min = pool_addr;
  233.     ipcp_p->peer_max = pool_addr + pool_cnt - 1;
  234.     return 0;
  235. }
  236.  
  237.  
  238. static int
  239. doipcp_remote(argc,argv,p)
  240. int argc;
  241. char *argv[];
  242. void *p;
  243. {
  244.     struct fsm_s *fsm_p = p;
  245.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  246.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  247. }
  248.  
  249.  
  250. /************************************************************************/
  251. /* Set addresses for PPP interface */
  252. static int
  253. doipcp_address(argc,argv,p)
  254. int argc;
  255. char *argv[];
  256. void *p;
  257. {
  258.     struct ipcp_side_s *side_p = p;
  259.     int32 x32;
  260.  
  261.     if (argc < 2) {
  262.         tprintf("%s\n", inet_ntoa(side_p->want.address));
  263.         return 0;
  264.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  265.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_ADDRESS,
  266.             "Allow Address", --argc, &argv[1] );
  267.     }
  268.     if ((x32 = resolve(argv[1])) == 0L) {
  269.         tprintf(Badhost,argv[1]);
  270.     }
  271.     side_p->want.address = x32;
  272.     side_p->want.negotiate |= IPCP_N_ADDRESS;
  273.     return 0;
  274. }
  275.  
  276.  
  277. /* Set IP compression type for PPP interface */
  278. static int
  279. doipcp_compress(argc,argv,p)
  280. int argc;
  281. char *argv[];
  282. void *p;
  283. {
  284.     struct ipcp_side_s *side_p = p;
  285.  
  286.     if (argc < 2) {
  287.         if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  288.             switch ( side_p->want.compression ) {
  289.             case PPP_COMPR_PROTOCOL:
  290.                 tprintf("TCP header compression enabled; "
  291.                     "Slots = %d, slot compress = %x\n",
  292.                     side_p->want.slots,
  293.                     side_p->want.slot_compress);
  294.                 break;
  295.             default:
  296.                 tprintf("0x%04x\n", side_p->want.compression);
  297.                 break;
  298.             };
  299.         } else {
  300.             tprintf("None\n");
  301.         }
  302.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  303.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_COMPRESS,
  304.             "Allow Compression", --argc, &argv[1] );
  305.     } else if ( stricmp(argv[1],"tcp") == 0
  306.          || stricmp(argv[1],"vj") == 0 ) {
  307.         side_p->want.compression = PPP_COMPR_PROTOCOL;
  308.         if ( argc >= 3 ) {
  309.             side_p->want.slots = strtol(argv[2],NULLCHARP,0);
  310.             if ( side_p->want.slots < 1 || side_p->want.slots > 255 ) {
  311.                 tprintf( "slots must be in range 1 to 255" );
  312.                 return 1;
  313.             }
  314.         } else {
  315.             side_p->want.slots = IPCP_SLOT_DEFAULT;
  316.         }
  317.         if ( argc >= 4 ) {
  318.             side_p->want.slot_compress = strtol(argv[3],NULLCHARP,0);
  319.         } else {
  320.             side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  321.         }
  322.         side_p->want.negotiate |= IPCP_N_COMPRESS;
  323.     } else if (stricmp(argv[1],"none") == 0) {
  324.         side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  325.     } else {
  326.         tprintf("allow tcp none\n");
  327.         return 1;
  328.     }
  329.     return 0;
  330. }
  331.  
  332.  
  333. static int
  334. doipcp_default(argc,argv,p)
  335. int argc;
  336. char *argv[];
  337. void *p;
  338. {
  339.     struct ipcp_side_s *side_p = p;
  340.  
  341.     ASSIGN( side_p->want, ipcp_default );
  342.     return 0;
  343. }
  344.  
  345.  
  346. /************************************************************************/
  347. /*            E V E N T   P R O C E S S I N G            */
  348. /************************************************************************/
  349.  
  350. static void
  351. ipcp_option(struct mbuf **bpp, struct ipcp_value_s *value_p,
  352.             byte_t o_type, byte_t o_length, struct mbuf **copy_bpp )
  353. {
  354.     struct mbuf *bp;
  355.     register char *cp;
  356.     register int toss = o_length - OPTION_HDR_LEN;
  357.  
  358.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  359.         return;
  360.     }
  361.     cp = bp->data;
  362.     *cp++ = o_type;
  363.     *cp++ = o_length;
  364.  
  365.     switch ( o_type ) {
  366.     case IPCP_ADDRESS:
  367.         cp = put32(cp, value_p->address);
  368.         cp = put32(cp, value_p->other);
  369.         toss -= 8;
  370. #ifdef PPP_DEBUG_OPTIONS
  371. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  372.     trace_log(PPPiface, "    making IP source address: %s",
  373.         inet_ntoa(value_p->address));
  374.     trace_log(PPPiface, "    making IP destination address %s",
  375.         inet_ntoa(value_p->other));
  376. }
  377. #endif
  378.         break;
  379.  
  380.     case IPCP_COMPRESS:
  381.         cp = put16(cp, value_p->compression);
  382.         toss -= 2;
  383. #ifdef PPP_DEBUG_OPTIONS
  384. if (PPPtrace & PPP_DEBUG_OPTIONS)
  385.     trace_log(PPPiface, "    making IP compression 0x%04x",
  386.         value_p->compression);
  387. #endif
  388.         if ( value_p->compression == PPP_COMPR_PROTOCOL ) {
  389.             *cp++ = value_p->slots - 1;
  390.             *cp++ = value_p->slot_compress;
  391.             toss -= 2;
  392. #ifdef PPP_DEBUG_OPTIONS
  393. if (PPPtrace & PPP_DEBUG_OPTIONS)
  394.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  395.         value_p->slots,
  396.         value_p->slot_compress);
  397. #endif
  398.         }
  399.         break;
  400.  
  401.     default:
  402. #ifdef PPP_DEBUG_OPTIONS
  403. if (PPPtrace & PPP_DEBUG_OPTIONS)
  404.     trace_log(PPPiface, "    making unimplemented type %d", o_type);
  405. #endif
  406.         break;
  407.     };
  408.  
  409.     while ( toss-- > 0 ) {
  410.         *cp++ = pullchar(copy_bpp);
  411.     }
  412.     bp->cnt += o_length;
  413.     append(bpp, bp);
  414. }
  415.  
  416.  
  417. /************************************************************************/
  418. /* Build a list of options */
  419. static void
  420. ipcp_makeoptions(struct mbuf **bpp, struct ipcp_value_s *value_p, int16 negotiating)
  421. {
  422.     register int o_type;
  423.  
  424.     PPP_DEBUG_ROUTINES("ipcp_makeoptions()");
  425.  
  426.     for ( o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++ ) {
  427.         if (negotiating & (1 << o_type)) {
  428.             ipcp_option( bpp, value_p,
  429.                 o_type, option_length[ o_type ], NULLBUFP);
  430.         }
  431.     }
  432. }
  433.  
  434.  
  435. /************************************************************************/
  436. /* Build a request to send to remote host */
  437. static struct mbuf *
  438. ipcp_makereq(fsm_p)
  439. struct fsm_s *fsm_p;
  440. {
  441.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  442.     struct mbuf *req_bp = NULLBUF;
  443.  
  444.     PPP_DEBUG_ROUTINES("ipcp_makereq()");
  445.  
  446.     ipcp_makeoptions( &req_bp, &(ipcp_p->local.work),
  447.                 ipcp_p->local.work.negotiate );
  448.     return(req_bp);
  449. }
  450.  
  451.  
  452. /************************************************************************/
  453. /* Check the options, updating the working values.
  454.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  455.  */
  456. static int
  457. ipcp_check( bpp, ipcp_p, side_p, option_p, request )
  458. struct mbuf **bpp;
  459. struct ipcp_s *ipcp_p;
  460. struct ipcp_side_s *side_p;
  461. struct option_hdr *option_p;
  462. int request;
  463. {
  464.     int toss = option_p->len - OPTION_HDR_LEN;
  465.     int option_result = CONFIG_ACK;        /* Assume good values */
  466.     int test;
  467.  
  468.     switch(option_p->type) {
  469.     case IPCP_ADDRESS:
  470.         side_p->work.address = pull32(bpp);
  471.         side_p->work.other = pull32(bpp);
  472.         toss -= 8;
  473. #ifdef PPP_DEBUG_OPTIONS
  474. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  475.     trace_log(PPPiface, "    checking IP source address: %s",
  476.         inet_ntoa(side_p->work.address));
  477.     trace_log(PPPiface, "    checking IP destination address %s",
  478.         inet_ntoa(side_p->work.other));
  479. }
  480. #endif
  481.         if ( !request ) {
  482.             /* override any undesirable changes */
  483.             if (ipcp_p->remote.want.address != 0L) {
  484.                 ipcp_p->local.work.other
  485.                     = ipcp_p->remote.want.address;
  486.             }
  487.             if (ipcp_p->local.want.address != 0L) {
  488.                 ipcp_p->local.work.address
  489.                     = ipcp_p->local.want.address;
  490.             }
  491.             break;
  492.         }
  493.  
  494.         /* Ensure that addresses match */
  495.         if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  496.             if (ipcp_p->remote.want.address == 0L) {
  497.                 /* don't know address either */
  498.                 option_result = CONFIG_REJ;
  499.             }
  500.         } else if (ipcp_p->remote.want.address == 0L) {
  501.             ipcp_p->local.work.other = ipcp_p->remote.work.address;
  502.         } else {
  503.             ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  504.             option_result = CONFIG_NAK;
  505.         }
  506.  
  507.         if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  508.             if (ipcp_p->local.want.address == 0L) {
  509.                 /* don't know address either */
  510.                 option_result = CONFIG_REJ;
  511.             }
  512.         } else if (ipcp_p->local.want.address == 0L) {
  513.             ipcp_p->local.work.address = ipcp_p->remote.work.other;
  514.         } else {
  515.             option_result = CONFIG_NAK;
  516.             ipcp_p->remote.work.other = ipcp_p->local.want.address;
  517.         }
  518.         break;
  519.  
  520.     case IPCP_COMPRESS:
  521.         side_p->work.compression = pull16(bpp);
  522.         toss -= 2;
  523. #ifdef PPP_DEBUG_OPTIONS
  524. if (PPPtrace & PPP_DEBUG_OPTIONS)
  525.     trace_log(PPPiface, "    checking IP compression 0x%04x",
  526.         side_p->work.compression);
  527. #endif
  528.         /* Check if requested type is acceptable */
  529.         switch ( side_p->work.compression ) {
  530.         case PPP_COMPR_PROTOCOL:
  531.             if ( (test = pullchar(bpp)) == -1 ) {
  532.                 return -1;
  533.             }
  534.             if ( (side_p->work.slots = test + 1) < IPCP_SLOT_LO) {
  535.                 side_p->work.slots = IPCP_SLOT_LO;
  536.                 option_result = CONFIG_NAK;
  537.             } else if (side_p->work.slots > IPCP_SLOT_HI) {
  538.                 side_p->work.slots = IPCP_SLOT_HI;
  539.                 option_result = CONFIG_NAK;
  540.             }
  541.  
  542.             if ( (test = pullchar(bpp)) == -1 ) {
  543.                 return -1;
  544.             }
  545.             if ( (side_p->work.slot_compress = test) > 1 ) {
  546.                 side_p->work.slot_compress = 1;
  547.                 option_result = CONFIG_NAK;
  548.             }
  549.             toss -= 2;
  550. #ifdef PPP_DEBUG_OPTIONS
  551. if (PPPtrace & PPP_DEBUG_OPTIONS)
  552.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  553.         side_p->work.slots,
  554.         side_p->work.slot_compress);
  555. #endif
  556.             break;
  557.  
  558.         default:
  559.             if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  560.                 side_p->work.compression = side_p->want.compression;
  561.                 side_p->work.slots = side_p->want.slots;
  562.                 side_p->work.slot_compress = side_p->want.slot_compress;
  563.             } else {
  564.                 side_p->work.compression = PPP_COMPR_PROTOCOL;
  565.                 side_p->work.slots = IPCP_SLOT_DEFAULT;
  566.                 side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  567.             }
  568.             option_result = CONFIG_NAK;
  569.             break;
  570.         };
  571.         break;
  572.  
  573.     default:
  574.         option_result = CONFIG_REJ;
  575.         break;
  576.     };
  577.  
  578.     if (option_p->type > IPCP_OPTION_LIMIT
  579.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  580.         option_result = CONFIG_REJ;
  581.     }
  582.  
  583.     if ( toss < 0 )
  584.         return -1;
  585.  
  586.     if ( !request  &&  toss > 0 ) {
  587.         /* toss extra bytes in option */
  588.         while( toss-- > 0 ) {
  589.             if ( pullchar(bpp) == -1 )
  590.                 return -1;
  591.         }
  592.     }
  593.  
  594.     return (option_result);
  595. }
  596.  
  597.  
  598. /************************************************************************/
  599. /* Check options requested by the remote host */
  600. static int
  601. ipcp_request(fsm_p, config, data)
  602. struct fsm_s *fsm_p;
  603. struct config_hdr *config;
  604. struct mbuf *data;
  605. {
  606.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  607.     int32 signed_length = config->len;
  608.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  609.     int reply_result = CONFIG_ACK;        /* reply to request */
  610.     int16 desired;                /* desired to negotiate */
  611.     struct option_hdr option;        /* option header storage */
  612.     int option_result;            /* option reply */
  613.  
  614.     PPP_DEBUG_ROUTINES("ipcp_request()");
  615.     ipcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  616.  
  617.     /* Process options requested by remote host */
  618.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  619.         if ((signed_length -= option.len) < 0) {
  620.             PPP_DEBUG_CHECKS("IPCP REQ: bad header length");
  621.             free_p(data);
  622.             free_p(reply_bp);
  623.             return -1;
  624.         }
  625.  
  626.         if ( ( option_result = ipcp_check( &data, ipcp_p,
  627.                 &(ipcp_p->remote), &option, TRUE ) ) == -1 ) {
  628.             PPP_DEBUG_CHECKS("IPCP REQ: ran out of data");
  629.             free_p(data);
  630.             free_p(reply_bp);
  631.             return -1;
  632.         }
  633.  
  634. #ifdef PPP_DEBUG_OPTIONS
  635. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  636.     trace_log(PPPiface, "IPCP REQ: result %s, option %d, length %d",
  637.         fsmCodes[option_result],
  638.         option.type,
  639.         option.len);
  640. }
  641. #endif
  642.         if ( option_result < reply_result ) {
  643.             continue;
  644.         } else if ( option_result > reply_result ) {
  645.             /* Discard current list of replies */
  646.             free_p(reply_bp);
  647.             reply_bp = NULLBUF;
  648.             reply_result = option_result;
  649.         }
  650.  
  651.         /* remember that we processed option */
  652.         if ( option_result != CONFIG_REJ
  653.          && option.type <= IPCP_OPTION_LIMIT ) {
  654.             ipcp_p->remote.work.negotiate |= (1 << option.type);
  655.         }
  656.  
  657.         /* Add option response to the return list */
  658.         ipcp_option( &reply_bp, &(ipcp_p->remote.work),
  659.             option.type, option.len, &data );
  660.     }
  661.  
  662.     /* Now check for any missing options which are desired */
  663.     if ( fsm_p->retry_nak > 0
  664.      &&  (desired = ipcp_p->remote.want.negotiate
  665.                & ~ipcp_p->remote.work.negotiate) != 0 ) {
  666.         switch ( reply_result ) {
  667.         case CONFIG_ACK:
  668.             free_p(reply_bp);
  669.             reply_bp = NULLBUF;
  670.             reply_result = CONFIG_NAK;
  671.             /* fallthru */
  672.         case CONFIG_NAK:
  673.             ipcp_makeoptions( &reply_bp, &(ipcp_p->remote.want),
  674.                 desired );
  675.             fsm_p->retry_nak--;
  676.             break;
  677.         case CONFIG_REJ:
  678.             /* do nothing */
  679.             break;
  680.         };
  681.     } else if ( reply_result == CONFIG_NAK ) {
  682.         /* if too many NAKs, reject instead */
  683.         if ( fsm_p->retry_nak > 0 )
  684.             fsm_p->retry_nak--;
  685.         else
  686.             reply_result = CONFIG_REJ;
  687.     }
  688.  
  689.     /* Send ACK/NAK/REJ to remote host */
  690.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  691.     free_p(data);
  692.     return (reply_result != CONFIG_ACK);
  693. }
  694.  
  695.  
  696. /************************************************************************/
  697. /* Process configuration ACK sent by remote host */
  698. static int
  699. ipcp_ack(fsm_p, config, data)
  700. struct fsm_s *fsm_p;
  701. struct config_hdr *config;
  702. struct mbuf *data;
  703. {
  704.     struct mbuf *req_bp;
  705.     int error = FALSE;
  706.  
  707.     PPP_DEBUG_ROUTINES("ipcp_ack()");
  708.  
  709.     /* ID field must match last request we sent */
  710.     if (config->id != fsm_p->lastid) {
  711.         PPP_DEBUG_CHECKS("IPCP ACK: wrong ID");
  712.         free_p(data);
  713.         return -1;
  714.     }
  715.  
  716.     /* Get a copy of last request we sent */
  717.     req_bp = ipcp_makereq(fsm_p);
  718.  
  719.     /* Overall buffer length should match */
  720.     if (config->len != len_p(req_bp)) {
  721.         PPP_DEBUG_CHECKS("IPCP ACK: buffer length mismatch");
  722.         error = TRUE;
  723.     } else {
  724.         register int req_char;
  725.         register int ack_char;
  726.  
  727.         /* Each byte should match */
  728.         while ((req_char = pullchar(&req_bp)) != -1) {
  729.             if ((ack_char = pullchar(&data)) == -1
  730.              || ack_char != req_char ) {
  731.                 PPP_DEBUG_CHECKS("IPCP ACK: data mismatch");
  732.                 error = TRUE;
  733.                 break;
  734.             }
  735.         }
  736.     }
  737.     free_p(req_bp);
  738.     free_p(data);
  739.  
  740.     if (error) {
  741.         return -1;
  742.     }
  743.  
  744.     PPP_DEBUG_CHECKS("IPCP ACK: valid");
  745.     return 0;
  746. }
  747.  
  748.  
  749. /************************************************************************/
  750. /* Process configuration NAK sent by remote host */
  751. static int
  752. ipcp_nak(fsm_p, config, data)
  753. struct fsm_s *fsm_p;
  754. struct config_hdr *config;
  755. struct mbuf *data;
  756. {
  757.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  758.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  759.     int32 signed_length = config->len;
  760.     struct option_hdr option;
  761.     int last_option = 0;
  762.     int result;
  763.  
  764.     PPP_DEBUG_ROUTINES("ipcp_nak()");
  765.  
  766.     /* ID field must match last request we sent */
  767.     if (config->id != fsm_p->lastid) {
  768.         PPP_DEBUG_CHECKS("IPCP NAK: wrong ID");
  769.         free_p(data);
  770.         return -1;
  771.     }
  772.  
  773.     /* First, process in order.  Then, process extra "important" options */
  774.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  775.         if ((signed_length -= option.len) < 0) {
  776.             PPP_DEBUG_CHECKS("IPCP NAK: bad header length");
  777.             free_p(data);
  778.             return -1;
  779.         }
  780.         if ( option.type > IPCP_OPTION_LIMIT ) {
  781.             PPP_DEBUG_CHECKS("IPCP NAK: option out of range");
  782.         } else if ( option.type < last_option
  783.          || !(local_p->work.negotiate & (1 << option.type)) ) {
  784.             if (local_p->work.negotiate & (1 << option.type)) {
  785.                 PPP_DEBUG_CHECKS("IPCP NAK: option out of order");
  786.                 free_p(data);
  787.                 return -1;        /* was requested */
  788.             }
  789.             local_p->work.negotiate |= (1 << option.type);
  790.             last_option = IPCP_OPTION_LIMIT + 1;
  791.         } else {
  792.             last_option = option.type;
  793.         }
  794.         if ( ( result = ipcp_check( &data, ipcp_p,
  795.                 local_p, &option, FALSE ) ) == -1 ) {
  796.             PPP_DEBUG_CHECKS("IPCP NAK: ran out of data");
  797.             free_p(data);
  798.             return -1;
  799.         }
  800.         /* update the negotiation status */
  801.         if ( result == CONFIG_REJ
  802.           && option.type <= IPCP_OPTION_LIMIT ) {
  803.             local_p->work.negotiate &= ~(1 << option.type);
  804.         }
  805.     }
  806.     PPP_DEBUG_CHECKS("IPCP NAK: valid");
  807.     free_p(data);
  808.     return 0;
  809. }
  810.  
  811.  
  812. /************************************************************************/
  813. /* Process configuration reject sent by remote host */
  814. static int
  815. ipcp_reject(fsm_p, config, data)
  816. struct fsm_s *fsm_p;
  817. struct config_hdr *config;
  818. struct mbuf *data;
  819. {
  820.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  821.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  822.     int32 signed_length = config->len;
  823.     struct option_hdr option;
  824.     int last_option = 0;
  825.  
  826.     PPP_DEBUG_ROUTINES("ipcp_reject()");
  827.  
  828.     /* ID field must match last request we sent */
  829.     if (config->id != fsm_p->lastid) {
  830.         PPP_DEBUG_CHECKS("IPCP REJ: wrong ID");
  831.         free_p(data);
  832.         return -1;
  833.     }
  834.  
  835.     /* Process in order, checking for errors */
  836.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  837.         register int k;
  838.  
  839.         if ((signed_length -= option.len) < 0) {
  840.             PPP_DEBUG_CHECKS("IPCP REJ: bad header length");
  841.             free_p(data);
  842.             return -1;
  843.         }
  844.         if ( option.type > IPCP_OPTION_LIMIT ) {
  845.             PPP_DEBUG_CHECKS("IPCP REJ: option out of range");
  846.         } else if (option.type < last_option
  847.          || !(local_p->work.negotiate & (1 << option.type))) {
  848.             PPP_DEBUG_CHECKS("IPCP REJ: option out of order");
  849.             free_p(data);
  850.             return -1;
  851.         }
  852.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  853.             if ( pullchar(&data) == -1 ) {
  854.                 PPP_DEBUG_CHECKS("IPCP REJ: ran out of data");
  855.                 free_p(data);
  856.                 return -1;
  857.             }
  858.         }
  859.         last_option = option.type;
  860.  
  861.         if ( option.type <= IPCP_OPTION_LIMIT ) {
  862.             local_p->work.negotiate &= ~(1 << option.type);
  863.         }
  864.     }
  865.     PPP_DEBUG_CHECKS("IPCP REJ: valid");
  866.     free_p(data);
  867.     return 0;
  868. }
  869.  
  870.  
  871. /************************************************************************/
  872. /*            I N I T I A L I Z A T I O N            */
  873. /************************************************************************/
  874.  
  875. /* Reset configuration options before request */
  876. static void
  877. ipcp_reset(fsm_p)
  878. struct fsm_s *fsm_p;
  879. {
  880.     struct ipcp_s *ipcp_p =    fsm_p->pdv;
  881.  
  882.     PPP_DEBUG_ROUTINES("ipcp_reset()");
  883.  
  884.     ASSIGN( ipcp_p->local.work, ipcp_p->local.want );
  885.     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  886.     ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  887.  
  888.     ipcp_p->remote.work.negotiate = FALSE;
  889.     ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  890. }
  891.  
  892.  
  893. /************************************************************************/
  894. /* After termination */
  895. static void
  896. ipcp_stopping(fsm_p)
  897. struct fsm_s *fsm_p;
  898. {
  899.     PPP_DEBUG_ROUTINES("ipcp_stopping()");
  900. }
  901.  
  902.  
  903. /************************************************************************/
  904. /* Close IPCP */
  905. static void
  906. ipcp_closing(fsm_p)
  907. struct fsm_s *fsm_p;
  908. {
  909.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  910.  
  911.     /* free old slhc configuration, if any */
  912.     slhc_free( ipcp_p->slhcp );
  913.     ipcp_p->slhcp = NULL;
  914.  
  915. #ifdef notdef
  916.     if (PPPtrace > 1)
  917.         trace_log(PPPiface,"%s PPP/IPCP Drop route to peer (%s)",
  918.             ifp->name,
  919.             inet_ntoa(ipcp_p->local.work.other));
  920.  
  921.     rt_drop(ipcp_p->local.work.other, (unsigned int)32);
  922. #endif
  923. }
  924.  
  925.  
  926. /************************************************************************/
  927. /* configuration negotiation complete */
  928. static void
  929. ipcp_opening(fsm_p)
  930. struct fsm_s *fsm_p;
  931. {
  932.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  933.     struct iface *ifp =         fsm_p->ppp_p->iface;
  934.     int32 address = ipcp_p->local.work.address;
  935.     int rslots = 0;
  936.     int tslots = 0;
  937.  
  938.     /* Set our IP address to reflect negotiated option */
  939.     if (address != ifp->addr) {
  940.         /* address not the same as last time */
  941.         if (Ip_addr == 0L) {
  942.             /* no global address */
  943.             Ip_addr = address;
  944.         } else if ( Ip_addr == ifp->addr ) {
  945.             /* global was same as local; must be replaced */
  946.             /* !!! TO DO: reset tcp connections */
  947.             Ip_addr = address;
  948.         }
  949.         ifp->addr = address;
  950.  
  951.         if (PPPtrace > 1)
  952.             trace_log(PPPiface,"%s PPP/IPCP Setting new IP address: %s",
  953.                 ifp->name,
  954.                 inet_ntoa(address));
  955.     }
  956.  
  957. #ifdef notdef
  958.     rt_add(ipcp_p->local.work.other, (unsigned int)32, (int32)0,
  959.         ifp, (int32)1, (int32)0, (char)1);
  960.  
  961.     if (PPPtrace > 1)
  962.         trace_log(PPPiface,"%s PPP/IPCP Add route to peer (%s)",
  963.             ifp->name,
  964.             inet_ntoa(ipcp_p->local.work.other));
  965. #endif
  966.  
  967.     /* free old slhc configuration, if any */
  968.     slhc_free( ipcp_p->slhcp );
  969.     ipcp_p->slhcp = NULL;
  970.  
  971.     if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS) {
  972.         rslots = ipcp_p->local.work.slots;
  973.     }
  974.     if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) {
  975.         tslots = ipcp_p->remote.work.slots;
  976.     }
  977.  
  978.     if ( rslots != 0 || tslots != 0 ) {
  979.         ipcp_p->slhcp = slhc_init( rslots, tslots );
  980.  
  981.         if (PPPtrace > 1)
  982.             trace_log(PPPiface,"%s PPP/IPCP Compression enabled;"
  983.                 " Recv slots = %d, flag = %x;"
  984.                 " Xmit slots = %d, flag = %x",
  985.                 ifp->name,
  986.                 rslots,
  987.                 ipcp_p->local.work.slot_compress,
  988.                 tslots,
  989.                 ipcp_p->remote.work.slot_compress);
  990.     }
  991. }
  992.  
  993.  
  994. /************************************************************************/
  995. /* Check the address against all other assigned addresses */
  996. static int32
  997. ipcp_addr_idle(addr)
  998. int32 addr;
  999. {
  1000.     struct iface *ifp;
  1001.  
  1002.     /* Check if peer IP address is already in use on another interface */
  1003.     /* !!! need to look at *remote* address, not local! */
  1004.     for (ifp=Ifaces; ifp != NULLIF; ifp = ifp->next) {
  1005.         if (ifp->addr == addr)
  1006.             return 0L;
  1007.     }
  1008.     return addr;
  1009. }
  1010.  
  1011.  
  1012. /************************************************************************/
  1013. /* Assign the next unused address from a pool */
  1014. static int32
  1015. ipcp_poolnext(ipcp_p)
  1016. struct ipcp_s *ipcp_p;
  1017. {
  1018.     int32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  1019.     int32 nextaddr = 0L;
  1020.  
  1021.     while ( i-- > 0  &&  nextaddr == 0L ) {
  1022.         if (++ipcp_p->local.want.other < ipcp_p->peer_min
  1023.          || ipcp_p->local.want.other > ipcp_p->peer_max)
  1024.             ipcp_p->local.want.other = ipcp_p->peer_min;
  1025.  
  1026.         nextaddr = ipcp_addr_idle(ipcp_p->local.want.other);
  1027.     }
  1028.     return(nextaddr);
  1029. }
  1030.  
  1031.  
  1032. /************************************************************************/
  1033. /* Check if we have a specific IP address to assign to remote peer host */
  1034. /* !!! TO DO: subnet mask, and routing */
  1035. static int32
  1036. ipcp_lookuppeer(peerid)
  1037. char *peerid;
  1038. {
  1039.     char *buf;
  1040.     int32 peer_addr = 0L;
  1041.  
  1042.     if (peerid == NULLCHAR)
  1043.         return 0L;
  1044.  
  1045.     if ( (buf = userlookup( peerid, NULLCHARP, NULLCHARP,
  1046.             NULL, &peer_addr )) != NULLCHAR ) {
  1047.         free(buf);
  1048.     }
  1049.     return(peer_addr);
  1050. }
  1051.  
  1052.  
  1053. /************************************************************************/
  1054. /* Prepare to begin configuration exchange */
  1055. static void
  1056. ipcp_starting(fsm_p)
  1057. struct fsm_s *fsm_p;
  1058. {
  1059.     struct ipcp_s *ipcp_p =        fsm_p->pdv;
  1060.  
  1061.     PPP_DEBUG_ROUTINES("ipcp_starting()");
  1062.  
  1063.     /* If not already set, and we know the name of the peer,
  1064.      * look in login file for an address
  1065.      */
  1066.     if ( ipcp_p->remote.want.address == 0L ){
  1067.         ipcp_p->remote.want.address
  1068.         = ipcp_lookuppeer(fsm_p->ppp_p->peername);
  1069.     }
  1070.  
  1071.     /* If available, get next address from PPP pool */
  1072.     if ((ipcp_p->remote.want.address == 0L)
  1073.      && (ipcp_p->peer_min != 0L)) {
  1074.         ipcp_p->remote.want.address = ipcp_poolnext(ipcp_p);
  1075.     }
  1076.  
  1077.     ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
  1078. }
  1079.  
  1080.  
  1081. /************************************************************************/
  1082. static void
  1083. ipcp_free(fsm_p)
  1084. struct fsm_s *fsm_p;
  1085. {
  1086.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  1087.  
  1088.     slhc_free( ipcp_p->slhcp );
  1089. }
  1090.  
  1091.  
  1092. /* Initialize configuration structure */
  1093. void
  1094. ipcp_init(ppp_p)
  1095. struct ppp_s *ppp_p;
  1096. {
  1097.     struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
  1098.     struct ipcp_s *ipcp_p;
  1099.  
  1100.     PPPtrace = ppp_p->trace;
  1101.     PPPiface = ppp_p->iface;
  1102.  
  1103.     PPP_DEBUG_ROUTINES("ipcp_init()");
  1104.  
  1105.     fsm_p->ppp_p = ppp_p;
  1106.     fsm_p->pdc = &ipcp_constants;
  1107.     fsm_p->pdv =
  1108.     ipcp_p = callocw(1,sizeof(struct ipcp_s));
  1109.  
  1110.     /* Set option parameters to first request defaults */
  1111.     ASSIGN( ipcp_p->local.want, ipcp_default );
  1112.     ipcp_p->local.will_negotiate = ipcp_negotiate;
  1113.  
  1114.     ASSIGN( ipcp_p->remote.want, ipcp_default );
  1115.     ASSIGN( ipcp_p->remote.work, ipcp_default);
  1116.     ipcp_p->remote.will_negotiate = ipcp_negotiate;
  1117.  
  1118.     fsm_init(fsm_p);
  1119. }
  1120.  
  1121.  
  1122.